/*
 * Created on 7. sep.. 2006
 * Created by Tomas
 */
package placing;

import java.util.List;
import java.util.Map;

import junit.framework.TestCase;

import org.junit.Before;
import org.junit.Test;

import people.Group;
import people.GroupNotFoundException;
import people.Person;
import people.PersonNotFoundException;
import util.Debug;

public class MapperTest extends TestCase{
	Mapper map;
	
	private Person hitler, stalin, churchill, eisenhower, degaulle, patton, rommel;
	private Group axis, allied;
	private Room germany, poland, russia, france, uk;
	private Place berlin, warsaw, moscow, london, dover, paris;

	@Before
	public void setUp() {
		map = new Mapper();
		
		hitler 		= new Person(1, "Adolf", "Hitler");
		stalin		= new Person(2, "Josef", "Stalin");
		churchill 	= new Person(3, "Winston", "Churchill");
		eisenhower 	= new Person(4, "Dwight D", "Eisenhower");
		degaulle 	= new Person(5, "Charles", "deGaulle");
		patton 		= new Person(6, "George S", "Patton");
		rommel 		= new Person(7, "Erwin", "Rommel");
		
		axis = new Group("Axis Powers", 24);
		allied = new Group("Allies of World War II", 10);
		
		germany = new Room(1, "Germany");
		poland = new Room(2, "Poland");
		russia = new Room(3, "Russia");
		france = new Room(4, "France");
		uk = new Room(5, "United Kingdom");
		
		berlin = new Place(germany, 1);
		warsaw = new Place(poland, 1);
		moscow = new Place(russia, 1);
		london = new Place(uk, 1);
		dover = new Place(uk, 3);
		paris = new Place(france, 1);
		
	}

	@Test
	public void testAddingEmptyRooms() throws RoomException{
		assertTrue(map.noRooms());
		
		map.addRoom(germany);
		map.addRoom();
		map.addRoom(24);
		
		
		assertFalse(map.noRooms());
		
		//Test that the Rooms are actually there
		assertTrue(map.isRoom(germany));
		assertTrue(map.isRoom(germany.getID()));
		assertEquals(3, map.numberOfRooms());
		assertEquals(24, map.numberOfPlaces());
		assertEquals(24, map.numberOfFreePlaces());
	}
	
	@Test
	public void testAddingFullRooms() throws RoomException, ReservationConflictException, PlaceNotFoundException{
		assertTrue(map.noRooms());
		
		for (int i = 0; i < 5; i++) {
			germany.addPlace();
		}
		
		map.addRoom(germany);
		
		assertEquals(5, map.numberOfPlaces());
		assertEquals(1, map.numberOfRooms());
		
		//4 new Places in a new Room, one occupied
		for (int i = 0; i < 4; i++) {
			poland.addPlace();
		}
		poland.getRandomFreePlace().assign(hitler);
		map.addRoom(poland);
		
		
		assertEquals(9, map.numberOfPlaces());
		assertEquals(2, map.numberOfRooms());
		assertEquals(8, map.numberOfFreePlaces());
		
	}
	
	@Test
	public void testAddingPlacesToRooms() throws RoomException, PlaceNotFoundException {
		assertTrue(map.noRooms());
		
		map.addRoom(germany);
		map.addRoom(france);
		map.addRoom(poland);
		
		map.addPlaces(3, france);
		assertEquals(3, map.numberOfFreePlaces());
		assertEquals(3, map.numberOfPlaces());
		assertEquals(3, map.numberOfRooms());
		

		map.addThisPlace(berlin, germany);
		
		assertEquals(4, map.numberOfPlaces());
		assertEquals(4, map.numberOfFreePlaces());
		assertEquals(3, map.numberOfRooms());
	}
	
	@Test
	public void testRemovingEmptyPlaces() throws RoomException, PlaceNotFoundException, ReservationConflictException {
		assertTrue(map.noRooms());
		
		map.addRoom(germany);
		map.addRoom(poland);
		map.addRoom(russia);
		map.addRoom(france);
		map.addRoom(uk);
		
		map.addPlaces(10, germany);
		map.addPlaces(10, poland);
		map.addPlaces(10, france);
		map.addPlaces(10, russia);
		map.addPlaces(10, uk);
		
		assertEquals(50, map.numberOfPlaces());
		assertEquals(map.numberOfFreePlaces(), map.numberOfPlaces());
		
		
		
		
		try {
			map.removePlaces(12, france);
			fail("Could remove 12 Places from Room with only 10 Places!");
		} catch (PlaceNotFoundException e) {
			// This should happen
		}
		
		map.removePlaces(5, france);
		assertEquals(45, map.numberOfPlaces());
		
		map.removeAllFreePlaces(germany);
		assertEquals(35, map.numberOfPlaces());
		
		Place testme = poland.getFreePlace();
		testme.assign(hitler);
		
		assertEquals(35, map.numberOfPlaces());
		assertEquals(34, map.numberOfFreePlaces());
		
		map.removeAllFreePlaces(poland.getID());
		
		assertEquals(25, map.numberOfFreePlaces());
		assertEquals(26, map.numberOfPlaces());
	}
	
	@Test
	public void testRemovingOccupiedPlaces() {
		// Test removing places with people in them
//		fail();
		// For now the Mapper is not allowed to remove places that are occupied
	}
	
	@Test
	public void testRemovingRooms() throws RoomException {
		assertTrue(map.noRooms());
		
		map.addRoom(germany);
		map.addRoom(poland);
		map.addRoom(russia);
		map.addRoom(france);
		map.addRoom(uk);
		
		assertFalse(map.noRooms());
		assertEquals(5, map.numberOfRooms());
		assertEquals(0, map.numberOfPlaces());
		
		map.removeRoom(germany);
		assertEquals(4, map.numberOfRooms());
		
		map.removeRoom(uk.getID());
		assertEquals(3, map.numberOfRooms());
		
		try {
			map.removeRoom(uk);
			fail("Removed UK two times, should not be possible");
		}
		catch (RoomException e) {
			//This should happen;
		}
	}
	
	@Test
	public void testAddingPeople() {
		map.addPerson(hitler);
		map.addPerson(stalin);
		map.addPerson(churchill);
		
		assertEquals(3, map.numberOfPersons());
	}
	
	@Test
	public void testRemovingPeople() throws PersonNotFoundException {
		testAddingPeople();
		
		assertEquals(3, map.numberOfPersons());
		
		map.removePerson(stalin);
		
		assertEquals(2, map.numberOfPersons());
		
		map.removePerson(hitler.getID());
		
		assertEquals(1, map.numberOfPersons());
		
	}
	
	@Test
	public void testAddingGroups() throws PersonNotFoundException {
		axis.addPerson(hitler);
		axis.addPerson(rommel);
		
		allied.addPerson(stalin);
		allied.addPerson(churchill);
		allied.addPerson(eisenhower);
		allied.addPerson(degaulle);
		
		assertTrue(map.noPeople());
		map.addGroup(allied);
		assertFalse(map.noPeople());
		
		assertEquals(4, map.numberOfPersons());
		
		allied.removePerson(degaulle);
		assertEquals(4, map.numberOfPersons());
		
		allied.addPerson(patton);
		assertEquals(4, map.numberOfPersons());
		
		map.addGroup(allied);
		assertEquals(4, map.numberOfPersons());
		
		map.addGroup(axis);
		assertEquals(6, map.numberOfPersons());
	}
	
	@Test
	public void testMembersToGroups() throws GroupNotFoundException {		
		allied.addPerson(stalin);
		allied.addPerson(churchill);
		allied.addPerson(eisenhower);
		allied.addPerson(degaulle);
		
		map.addGroup(axis);
		map.addGroup(allied);
		
		assertEquals(4, map.numberOfPersons());
		
		map.addPerson(hitler);
		map.assignPersonToGroup(hitler, axis);
		
		assertEquals(hitler, map.getGroup(axis.getName()).getPersons().get(0));
		
		map.removePersonFromGroup(stalin, allied);
		
		Group g = map.getGroup(allied.getName());
		if (g.inGroup(stalin)) {
			fail("Stalin was not removed from group");
		}
		if (allied.inGroup(stalin)) {
			fail("Stalin was not removed from Allies");
		}
		
	}
	
	@Test
	public void testReservations() throws RoomException, PlaceNotFoundException,
	ReservationConflictException {

		axis.addPerson(hitler);
		axis.addPerson(rommel);
		
		allied.addPerson(stalin);
		allied.addPerson(churchill);
		allied.addPerson(eisenhower);
		allied.addPerson(degaulle);
		
		map.addGroup(axis);
		map.addGroup(allied);
		map.addPerson(patton); //lonely person
		
		map.addRoom(germany);
		map.addRoom(poland);
		map.addRoom(russia);
		map.addRoom(france);
		map.addRoom(uk);
		
		map.addPlaces(3, germany);
		map.addPlaces(2, poland);
		map.addPlaces(5, russia);

		
		map.reserveRoom(germany, axis);
		map.reservePlaceInRoom(germany, patton);
		map.reserveRoom(russia, stalin);
		
		assertFalse(map.isValid(stalin, germany.getFreePlace()));
		
		List<Place> placesGermany = germany.getPlaces();
		
		//check that Patton has one reservation in Germany
		int count = 0;
		for (Place p : placesGermany) {
			if (p.isValidAndFree(patton)) {
				count++;
			}
		}
		
		assertEquals(1, count);
		
//		Debug.ON = true;
		if (Debug.ON) {
			System.out.println("\n\ttestReservations\n");
			System.out.println("Map so far:");
		}		
		printout();
		map.distributePersonsToPlaces();
		
		
		if (Debug.ON) {
			System.out.println("\n\tEnd of testReservations()\n");
		}
		printout();
		Debug.ON = false;
	}
	
	@Test
	public void testPlacingPerson() throws RoomException, PlaceNotFoundException,
	PersonNotFoundException, ReservationConflictException {
		axis.addPerson(hitler);
		axis.addPerson(rommel);
		
		allied.addPerson(stalin);
		allied.addPerson(churchill);
		allied.addPerson(eisenhower);
		allied.addPerson(degaulle);
		
		map.addGroup(axis);
		map.addGroup(allied);
		map.addPerson(patton); //lonely person
		
		map.addRoom(germany);
		map.addRoom(poland);
		map.addRoom(russia);
		map.addRoom(france);
		map.addRoom(uk);
		
		map.addPlaces(2, germany);
		map.addThisPlace(berlin, germany);
		
		map.addPlaces(1, poland);
		map.addThisPlace(warsaw, poland);
		
		map.addPlaces(2, france);
		map.addThisPlace(paris, france);
		
		map.addPlaces(1, russia);
		map.addThisPlace(moscow, russia);
		
		map.addPlaces(3, uk);
		map.addThisPlace(london, uk);
		map.addThisPlace(dover, uk);
		
		assertEquals(5, map.numberOfRooms());
		assertEquals(9, map.numberOfPlaces());
		assertEquals(7, map.numberOfPersons());
		
		
		hitler.addPreferredPlace(berlin);
		churchill.addPreferredPlace(london);
		stalin.addPreferredPlace(moscow);
		patton.addPreferredPlace(berlin);
		
		map.grantPersonPlace(patton);
		map.grantGroupPlace(allied);
		map.grantPersonPlace(eisenhower);
		
		map.grantGroupPlace(axis);
		
		printout();
		
		assertEquals(hitler, berlin.getCurrent());
		assertEquals(churchill, london.getCurrent());
		assertEquals(stalin, moscow.getCurrent());
		assertEquals(7, map.numberOfPersons());
		assertEquals(2, map.numberOfFreePlaces());
	}
	
	@Test
	public void testAssignAll() throws RoomException, PlaceNotFoundException, ReservationConflictException {
		axis.addPerson(hitler);
		axis.addPerson(rommel);
		
		allied.addPerson(stalin);
		allied.addPerson(churchill);
		allied.addPerson(eisenhower);
		allied.addPerson(degaulle);
		
		map.addGroup(axis);
		map.addGroup(allied);
		map.addPerson(patton); //lonely person
		
		map.addRoom(germany);
		map.addRoom(poland);
		map.addRoom(russia);
		map.addRoom(france);
		map.addRoom(uk);
		
		map.addPlaces(1, germany);
		map.addThisPlace(berlin, germany);
		
		map.addPlaces(1, poland);
		map.addThisPlace(warsaw, poland);
		
		map.addPlaces(1, france);
		map.addThisPlace(paris, france);
		
		map.addPlaces(1, russia);
		map.addThisPlace(moscow, russia);
		
		map.addPlaces(2, uk);
		map.addThisPlace(london, uk);
		map.addThisPlace(dover, uk);
		
		assertEquals(7, map.numberOfPersons());
		assertEquals(7, map.numberOfFreePlaces());
		assertEquals(7, map.numberOfPlaces());
		
		map.distributePersonsToPlaces();
		
		assertEquals(7, map.numberOfPlaces());
		assertEquals(0, map.numberOfFreePlaces());
	}
	
	//getMap
	@Test
	public void testGetMap() throws RoomException, PlaceNotFoundException, ReservationConflictException {
		axis.addPerson(hitler);
		axis.addPerson(rommel);
		
		allied.addPerson(stalin);
		allied.addPerson(churchill);
		allied.addPerson(eisenhower);
		allied.addPerson(degaulle);
		
		map.addGroup(axis);
		map.addGroup(allied);
		map.addPerson(patton); //lonely person
		
		map.addRoom(germany);
		map.addRoom(poland);
		map.addRoom(russia);
		map.addRoom(france);
		map.addRoom(uk);
		
		map.addPlaces(1, germany);
		map.addThisPlace(berlin, germany);
		
		map.addPlaces(1, poland);
		map.addThisPlace(warsaw, poland);
		
		map.addPlaces(1, france);
		map.addThisPlace(paris, france);
		
		map.addPlaces(1, russia);
		map.addThisPlace(moscow, russia);
		
		map.addPlaces(2, uk);
		map.addThisPlace(london, uk);
		map.addThisPlace(dover, uk);
		
		
		map.distributePersonsToPlaces();
		
		Debug.ON = true;
		
		Map<Person, Place> resultingMap = map.getMap();
		printMap(resultingMap);
		
	}
	
	
	
	@Test
	public void testDataExport() {
		//TODO Test that data exports correctly
		fail();
	}
	
	@Test
	public void testDataImport() {
		//TODO Test importing of data
		fail();
	}
	
	@Test
	public void testGettingNamedPlcae() throws Exception {
		testGetMap();
		
		assertEquals(london, map.getPlace(london.getPlaceName()));
	}

	private void printout() {
		if (Debug.ON) {
			map.printout();
		}
		
	}

	private void printMap(Map<Person, Place> map) {
		if (Debug.ON) {
			System.out.println("Map (" + map.size() + ")");
			for (Map.Entry<Person, Place> entry : map.entrySet()) {
				System.out.println(entry.getKey().getName() + ": " + entry.getValue().getPlaceName());
			}
		}
		
	}
}
